#include "glwidget.h"

void GLWidget::ObjectToCSG(CellObject *a, CSG *b)
{
    a->transformVertex();
    vector<MyPolygon> pa;
    for (int i=0;i<a->getFaceNum();i++) {
        Vertex3 v0 = Vertex3(a->getVertice(a->getFace(i*3+0)), a->getNormal(a->getFace(i*3+0)));
        Vertex3 v1 = Vertex3(a->getVertice(a->getFace(i*3+1)), a->getNormal(a->getFace(i*3+1)));
        Vertex3 v2 = Vertex3(a->getVertice(a->getFace(i*3+2)), a->getNormal(a->getFace(i*3+2)));
        vector<Vertex3> v;
        v.push_back(v0);
        v.push_back(v1);
        v.push_back(v2);
        MyPolygon p = MyPolygon(v, 0.0);
        pa.push_back(p);
    }
    b->polygons = pa;
}

void GLWidget::CSGToObject(CSG *a, CellObject *b)
{
    int f_num = 0;
    int v_num = 0;
    for (size_t i=0;i<a->polygons.size();i++) {
        f_num += (a->polygons[i]).vertices.size()-2;
        v_num += (a->polygons[i]).vertices.size();
    }
    int *face = new int[f_num*3];
    double *ver = new double[v_num*3];
    double *nor = new double[v_num*3];
    int fn = 0;
    int vn = 0;
    for (size_t i=0;i<a->polygons.size();i++) {
        int tmpvn = (a->polygons[i]).vertices.size();
        for (int k=2;k<tmpvn;k++) {
            face[fn*3+0] = vn;
            face[fn*3+1] = vn+k-1;
            face[fn*3+2] = vn+k;
            fn++;
        }
        for (int k=0;k<tmpvn;k++) {
            ver[vn*3+0] = (a->polygons[i]).vertices[k].pos.x;
            ver[vn*3+1] = (a->polygons[i]).vertices[k].pos.y;
            ver[vn*3+2] = (a->polygons[i]).vertices[k].pos.z;
            nor[vn*3+0] = (a->polygons[i]).vertices[k].normal.x;
            nor[vn*3+1] = (a->polygons[i]).vertices[k].normal.y;
            nor[vn*3+2] = (a->polygons[i]).vertices[k].normal.z;
            vn++;
        }
        for (int k=2;k<tmpvn;k++) {
            Vector3 v0 = Vector3(ver[face[(fn-tmpvn+k)*3+0]*3+0], ver[face[(fn-tmpvn+k)*3+0]*3+1], ver[face[(fn-tmpvn+k)*3+0]*3+2]);
            Vector3 v1 = Vector3(ver[face[(fn-tmpvn+k)*3+1]*3+0], ver[face[(fn-tmpvn+k)*3+1]*3+1], ver[face[(fn-tmpvn+k)*3+1]*3+2]);
            Vector3 v2 = Vector3(ver[face[(fn-tmpvn+k)*3+2]*3+0], ver[face[(fn-tmpvn+k)*3+2]*3+1], ver[face[(fn-tmpvn+k)*3+2]*3+2]);
            Vector3 tmpn = Cross(v1-v0, v2-v0);
            Vector3 normal =  Vector3(nor[face[(fn-tmpvn+k)*3+0]*3+0], nor[face[(fn-tmpvn+k)*3+0]*3+1], nor[face[(fn-tmpvn+k)*3+0]*3+2]);
            if (Dot(tmpn, normal)<0) {
                int tmp = face[(fn-tmpvn+k)*3+0];
                face[(fn-tmpvn+k)*3+0] = face[(fn-tmpvn+k)*3+1];
                face[(fn-tmpvn+k)*3+1] = tmp;
            }
        }
    }
    b->buildObject(v_num, f_num, ver, nor, face);
}

void GLWidget::Union(CellObject *a, CellObject *b, CellObject *result)
{
    CellObject *a_copy = new CellObject();
    CellObject *b_copy = new CellObject();
    a_copy = a->clone();
    b_copy = b->clone();
    a_copy->toCSG();
    b_copy->toCSG();
    result->setCSG(a_copy->getCSG()->csg_union(b_copy->getCSG()));
    result->toObject();
    delete a_copy;
    delete b_copy;

//    CSG *csga = new CSG();
//    CSG *csgb = new CSG();
//    CSG *csgc = new CSG();
//    ObjectToCSG(a, csga);
//    ObjectToCSG(b, csgb);
//    csgc = csga->csg_union(csgb);
//    CSGToObject(csgc, result);
}

void GLWidget::Intersect(CellObject *a, CellObject *b, CellObject *result)
{
    CellObject *a_copy = new CellObject();
    CellObject *b_copy = new CellObject();
    a_copy = a->clone();
    b_copy = b->clone();
    a_copy->toCSG();
    b_copy->toCSG();
    result->setCSG(a_copy->getCSG()->csg_intersect(b_copy->getCSG()));
    result->toObject();
    delete a_copy;
    delete b_copy;

//    CSG *csga = new CSG();
//    CSG *csgb = new CSG();
//    CSG *csgc = new CSG();
//    ObjectToCSG(a, csga);
//    ObjectToCSG(b, csgb);
//    csgc = csga->csg_intersect(csgb);
//    CSGToObject(csgc, result);
}

void GLWidget::Subtract(CellObject *a, CellObject *b, CellObject *result)
{
    CellObject *a_copy = new CellObject();
    CellObject *b_copy = new CellObject();
    a_copy = a->clone();
    b_copy = b->clone();
    a_copy->toCSG();
    b_copy->toCSG();
    result->setCSG(a_copy->getCSG()->csg_subtract(b_copy->getCSG()));
    result->toObject();
    delete a_copy;
    delete b_copy;

//    CSG *csga = new CSG();
//    CSG *csgb = new CSG();
//    CSG *csgc = new CSG();
//    ObjectToCSG(a, csga);
//    ObjectToCSG(b, csgb);
//    csgc = csga->csg_subtract(csgb);
//    CSGToObject(csgc, result);
}

void GLWidget::Union()
{
    if (selectObject<2||secondSelectObject<2||selectObject==secondSelectObject)
        return;
    CellObject *result = new CellObject();
    Union(objects[selectObject-2], objects[secondSelectObject-2], result);
    if (selectObject<secondSelectObject) {
        objects.erase(objects.begin()+(selectObject-2));
        objects.erase(objects.begin()+(secondSelectObject-3));
    } else {
        objects.erase(objects.begin()+(selectObject-2));
        objects.erase(objects.begin()+(secondSelectObject-2));
    }
    objects.push_back(result);
    //cout << "gliwidget_csg1: " << selectObject << endl;
    selectObject = objects.size()-1+2;
    //cout << "gliwidget_csg1: " << selectObject << endl;
    secondSelectObject = -1;
    setInputType();
}

void GLWidget::Subtract()
{
    if (selectObject<2||secondSelectObject<2||selectObject==secondSelectObject)
        return;
    CellObject *result = new CellObject();
    Subtract(objects[selectObject-2], objects[secondSelectObject-2], result);
    if (selectObject<secondSelectObject) {
        objects.erase(objects.begin()+(selectObject-2));
        objects.erase(objects.begin()+(secondSelectObject-3));
    } else {
        objects.erase(objects.begin()+(selectObject-2));
        objects.erase(objects.begin()+(secondSelectObject-2));
    }
    objects.push_back(result);
    //cout << "gliwidget_csg2: " << selectObject << endl;
    selectObject = objects.size()-1+2;
    //cout << "gliwidget_csg2: " << selectObject << endl;
    secondSelectObject = -1;
    setInputType();
}

void GLWidget::Intersect()
{
    if (selectObject<2||secondSelectObject<2||selectObject==secondSelectObject)
        return;
    CellObject *result = new CellObject();
    Intersect(objects[selectObject-2], objects[secondSelectObject-2], result);
    if (selectObject<secondSelectObject) {
        objects.erase(objects.begin()+(selectObject-2));
        objects.erase(objects.begin()+(secondSelectObject-3));
    } else {
        objects.erase(objects.begin()+(selectObject-2));
        objects.erase(objects.begin()+(secondSelectObject-2));
    }
    objects.push_back(result);
    //cout << "gliwidget_csg3: " << selectObject << endl;
    selectObject = objects.size()-1+2;
    //cout << "gliwidget_csg3: " << selectObject << endl;
    secondSelectObject = -1;
    setInputType();
}

void GLWidget::test()
{
    CellObject *cube = new CellObject();
    cube->buildCube(0.0, 0.0, 0.0, 0, 0, 0);
    cube->setTranslateY(3);
    CellObject *sphere = new CellObject();
    sphere->buildSphere(0.0, 0, 0);
    CellObject *cylinder = new CellObject();
    cylinder->buildCylinder(0.0, 0.0, 0, 0);
    CellObject *result = new CellObject();
    CellObject *result2 = new CellObject();
    Union(cylinder, cube, result);
    Union(sphere, result, result2);
    objects.push_back(result2);
    updateGL();
}

